<style lang="scss">
.ua-file {
  width: 100%;
  height: 120px;
  display: flex;
  &--select {
    width: 150px;
    height: 100%;
    position: relative;
    display: inline-block;
    border: 1px dashed #e2e2e2;
    text-align: center;
    padding: 20px;
    box-sizing: border-box;
    cursor: pointer;
    flex-shrink: 0;
    & > input[type='file'] {
      display: inline-block;
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
      opacity: 0;
      cursor: pointer;
    }
    &-icon {
      & > span {
        display: inline-block;
        width: 100%;
        text-align: center;
        color: #999;
        font-size: 12px;
        line-height: 1.5;
      }
    }
  }
  &--preview {
    flex-grow: 1;
    height: 100%;
    overflow: hidden;
    &-item {
      display: inline-block;
      height: 100%;
      margin-left: 10px;
    }
  }
}
.ua-media-file {
  & > .ua-file--select {
    margin-right: 10px;
  }
}
</style>

<template>
  <div class="ua-file ua-media-file">
    <div class="ua-file--select">
      <input
        type="file"
        ref="mediaAccept"
        :accept="mediaAccept"
        @change="onChange($event)"
      />
      <div class="ua-file--select-icon">
        <UIconfont :name="`${media}-file`" :size="50" color="#009688" />
        <span>选择{{ title }}文件</span>
      </div>
    </div>
    <div class="ua-file--select" v-if="!noPoster">
      <input
        type="file"
        ref="posterInput"
        :accept="posterAccept"
        @change="onChange($event, true)"
      />
      <div class="ua-file--select-icon">
        <UIconfont name="image-file" :size="50" color="#009688" />
        <span>选择{{ title }}封面</span>
      </div>
    </div>
    <UMediaLazy
      :media="media"
      :no-poster="noPoster"
      :width="mediaWidth"
      :height="mediaHeight"
      :play-icon-size="playIconSize"
      :src="mediaFile"
      :poster="posterFile"
    />
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, PropType, ref, Ref } from 'vue'
import UIconfont from './UIconfont.vue'
import UMediaLazy from './UMediaLazy.vue'

export default defineComponent({
  name: 'UMediaFile',
  components: { UIconfont, UMediaLazy },
  props: {
    mediaAccept: {
      type: String,
      default: 'audio/*',
      values: [
        'audio/*',
        'audio/aac',
        'audio/midi',
        'audio/x-midi',
        'audio/midi',
        'audio/x-midi',
        'audio/mpeg',
        'audio/ogg',
        'audio/wav',
        'audio/webm',
        'audio/3gpp',
        'audio/3gpp2',
        'video/*',
        'video/x-msvideo',
        'video/mpeg',
        'video/ogg',
        'video/webm',
        'video/3gpp',
        'video/3gpp2',
        'video/mp4',
      ],
    },
    posterAccept: {
      type: String,
      default: 'image/*',
      values: [
        'image/*',
        'image/bmp',
        'image/gif',
        'image/vnd.microsoft.icon',
        'image/jpeg',
        'image/jpeg',
        'image/png',
        'image/svg+xml',
        'image/tiff',
        'image/tiff',
        'image/webp',
      ],
    },
    noPoster: {
      type: Boolean,
      default: false,
    },
    mediaWidth: {
      type: Number,
      default: 150,
    },
    mediaHeight: {
      type: Number,
      default: 120,
    },
    playIconSize: {
      type: Number,
      default: 50,
    },
    playIconColor: {
      type: String,
      default: '#009688',
    },
    src: {
      type: String,
      default: '',
    },
    poster: {
      type: String,
      default: '',
    },
    upload: {
      type: Function as PropType<UMediaFileUploadCallback>,
    },
    mediaRequired: {
      type: Boolean,
      default: false,
    },
    posterRequired: {
      type: Boolean,
      default: false,
    },
  },
  setup(props) {
    // 媒体类型
    const media = computed(() => (/audio/.test(props.mediaAccept) ? 'audio' : 'video'))
    // 文件类型的标题
    const title = computed(() => (media.value === 'audio' ? '音频' : '视频'))
    // 媒体文件
    const mediaFile = ref(props.src) as Ref<string | File>
    // 封面文件
    const posterFile = ref(props.poster) as Ref<string | File>
    /**
     * input[file].onchange
     */
    function onChange(event: Event, poster = false) {
      const temp = Array.from((event.target as HTMLInputElement).files!)
      if (temp.length) {
        if (poster) {
          posterFile.value = temp[0]
        } else {
          mediaFile.value = temp[0]
        }
      } else {
        if (poster) {
          posterFile.value = props.poster
        } else {
          mediaFile.value = props.src
        }
      }
    }
    /**
     * 表单验证，供父组件调用
     */
    function validate() {
      if (props.mediaRequired && !props.src && !mediaFile.value) {
        return Promise.reject(new Error(`${title.value}未选择`))
      }
      if (props.posterRequired && !props.poster && !posterFile.value) {
        return Promise.reject(new Error(`${title.value}封面未选择`))
      }
      if (typeof props.upload !== 'function') {
        return Promise.reject(new Error('未定义文件上传函数！！！'))
      }
      return Promise.resolve()
    }
    /**
     * 执行文件上传，供父组件调用
     */
    function submit() {
      return new Promise<void>((resolve, reject) => {
        validate().then(() => {
          props.upload!(
            mediaFile.value instanceof File ? mediaFile.value : null,
            posterFile.value instanceof File ? posterFile.value : null
          ).then(resolve, reject)
        }, reject)
      })
    }

    return { media, title, mediaFile, posterFile, onChange, submit, validate }
  },
})
</script>
